source <(fzf --zsh)

# Use back slash '\' as the trigger sequence instead of the default **
export FZF_COMPLETION_TRIGGER='\'

# Setting fd as the default source for fzf
# export FZF_DEFAULT_COMMAND="rg -g '!{.git,.svn,node_modules}' --hidden ''"
export FZF_DEFAULT_COMMAND='fd --strip-cwd-prefix --hidden --follow'

# export FZF_DEFAULT_OPTS="--layout=reverse --bind ctrl-/:toggle-preview,ctrl-d:preview-down,ctrl-s:preview-up"
# export FZF_DEFAULT_OPTS=$FZF_DEFAULT_OPTS'
#   --color=hl:#72a4ff,hl+:#87ff00,pointer:#87ff00,prompt:#87ff00'

export MY_FZF_DEFAULT_OPTS="--layout=reverse --cycle --bind ctrl-/:toggle-preview,alt-\>:last,alt-\<:first"
export MY_FZF_DEFAULT_COLOR='
  --color=hl:#72a4ff,hl+:#87ff00,pointer:#87ff00,prompt:#87ff00'
export FZF_DEFAULT_OPTS=$MY_FZF_DEFAULT_OPTS$MY_FZF_DEFAULT_COLOR

# ALT-C - cd into the selected directory
export FZF_ALT_C_OPTS="--preview 'tree -C {} | head -200'"

# CTRL-T - Paste the selected file path(s) into the command line
export FZF_CTRL_T_OPTS='--preview "[[ $(file --mime {}) =~ binary ]] && (file -i {}) || ( bat --style=plain --color=always -r :500 {} || cat {}) 2> /dev/null | head -500"'

# CTRL-R - Paste the selected command from history into the command line
# use --with-nth 2.. to hide history number, see https://github.com/junegunn/fzf/issues/3007#issuecomment-2143192837
export FZF_CTRL_R_OPTS="--with-nth 2.. --height 40% --layout=reverse --info=hidden --no-separator --bind=tab:down,ctrl-r:toggle-sort,ctrl-k:kill-line"
my-fzf-history-widget() {
  local selected
  setopt localoptions noglobsubst noposixbuiltins pipefail no_aliases noglob nobash_rematch 2> /dev/null
  # Ensure the associative history array, which maps event numbers to the full
  # history lines, is loaded, and that Perl is installed for multi-line output.
  if zmodload -F zsh/parameter p:{commands,history} 2>/dev/null && (( ${+commands[perl]} )); then
    selected="$(printf '%s\t%s\000' "${(kv)history[@]}" |
      perl -0 -ne 'if (!$seen{(/^\s*[0-9]+\**\t(.*)/s, $1)}++) { s/\n/\n\t/g; print; }' |
      FZF_DEFAULT_OPTS=$(__fzf_defaults "" "-n2..,.. --scheme=history --bind=ctrl-r:toggle-sort --highlight-line --expect=ctrl-e ${FZF_CTRL_R_OPTS-} --query=${(qqq)LBUFFER} +m --read0") \
      FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd))"
  else
    selected="$(fc -rl 1 | awk '{ cmd=$0; sub(/^[ \t]*[0-9]+\**[ \t]+/, "", cmd); if (!seen[cmd]++) print $0 }' |
      FZF_DEFAULT_OPTS=$(__fzf_defaults "" "-n2..,.. --scheme=history --bind=ctrl-r:toggle-sort --highlight-line --expect=ctrl-e ${FZF_CTRL_R_OPTS-} --query=${(qqq)LBUFFER} +m") \
      FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd))"
  fi
  local ret=$?
  if [ -n "$selected" ]; then
    local accept=0
    if [[ $(awk '{print $1; exit}' <<< "$selected") =~ ^'ctrl-e' ]]; then
        accept=1
    fi
    if [[ $(awk 'NR==2 {print $1; exit}' <<< "$selected") =~ ^[1-9][0-9]* ]]; then
      zle vi-fetch-history -n $MATCH
      [[ $accept = 0 ]] && zle accept-line
    else # selected is a custom query, not from history
      LBUFFER="$selected"
    fi
  fi
  zle reset-prompt
  return $ret
}
zle     -N   my-fzf-history-widget
bindkey '^R' my-fzf-history-widget


# FZF jump around
# ---------------------------------------------------------------------
fe() {
  out=$(fd --type f -H 2> /dev/null | fzf -m --height 40% --reverse --no-preview --expect=ctrl-o,ctrl-e)
  key=$(head -1 <<< "$out")
  IFS=$'\n' files=($(tail -n+2 <<< "$out"))
  if [ -n "$files" ]; then
    [ "$key" = ctrl-o ] && gio open "${files[@]}" || ${EDITOR:-vim} "${files[@]}"
  fi
}

fdd() {
  local dir
  dir=$(fd --type d -H 2> /dev/null | fzf --height 40% --reverse --no-preview +m) && cd "$dir"
}

j() {
  cd "$(z -l "$@" | fzf --with-nth 2.. --reverse --no-preview --bind='tab:down' --inline-info --tac +s -e --height 35% | sed 's/^[0-9,.]* *//')"
}


# FZF work with Virtualenv
# ---------------------------------------------------------------------
_fzf_complete_acv() {
  dirs=$(find ~/.virtualenvs -maxdepth 1 -mindepth 1 -type d | awk -F"./" '{print $4}')
  _fzf_complete "--no-preview --reverse" "$@" < <(
    echo $dirs
  )
}


# FZF work with Git
# ---------------------------------------------------------------------
_fzf_complete_gl() {
  branches=$(git branch -vv --all)
  _fzf_complete "--no-preview --reverse" "$@" < <(
    echo $branches
  )
}
_fzf_complete_gl_post() {
  awk '{if ($1 ~ /[\*+]/) print $2; else print $1}'
}

_fzf_complete_gsc() {
  branches=$(git branch -vv --all)
  _fzf_complete "--no-preview --reverse" "$@" < <(
    echo $branches
  )
}
_fzf_complete_gsc_post() {
  awk '{if ($1 ~ /[\*+]/) print $2; else print $1}'
}

is_in_git_repo() {
  git rev-parse HEAD > /dev/null 2>&1
}

gh() {
  is_in_git_repo || return
  git log --date=short --format="%C(green)%C(bold)%cd %C(auto)%h%d %s (%an)" --graph --color=always |
  fzf --height 80% --border --ansi --no-sort --reverse --multi --bind 'ctrl-s:toggle-sort,down:preview-down,up:preview-up' \
    --header 'Press CTRL-S to toggle sort' \
    --preview 'grep -o "[a-f0-9]\{7,\}" <<< {} | xargs git show --color=always | head -'$LINES |
  grep -o "[a-f0-9]\{7,\}"
}

gk() {
  is_in_git_repo || return
  if [ $# -eq 0 ]; then
    git_br_args=--all
  else
    git_br_args=$@
  fi
  git log --graph --color=always --abbrev-commit --decorate \
    --format=format:'%C(blue)%h%C(reset) - %C(green)(%ar)%C(reset) %s %C(dim white)- %an%C(reset)%C(yellow)%d%C(reset)' \
    $git_br_args |
  fzf --ansi --no-sort --reverse --tiebreak=index --bind 'ctrl-s:toggle-sort,ctrl-d:page-down,ctrl-u:page-up,alt->:last,alt-<:first,tab:down,ctrl-k:kill-line' \
    --preview 'grep -o "[a-f0-9]\{7,\}" <<< {} | xargs git show --color=always | head -'$LINES \
    --bind "ctrl-m:execute:
              (grep -o '[a-f0-9]\{7\}' | head -1 |
              xargs -I % sh -c 'git show --color=always % | less -R') << 'FZF-EOF'
              {}
FZF-EOF" \
    --bind "ctrl-j:execute:
              (grep -o '[a-f0-9]\{7\}' | head -1 |
              xargs -I % sh -c 'git difftool --no-prompt % %~') << 'FZF-EOF'
              {}
FZF-EOF" \
    --bind "ctrl-o:execute:
              (grep -o '[a-f0-9]\{7\}' | head -1 |
              xargs -I % sh -c 'git show % | nvim -') << 'FZF-EOF'
              {}
FZF-EOF"

  return 0
}

_fzf_complete_gk() {
  branches=$(git branch -vv --all)
  _fzf_complete "--no-preview --reverse" "$@" < <(
    echo $branches
  )
}

_fzf_complete_gk_post() {
  awk '{if ($1 ~ /[\*+]/) print $2; else print $1}'
}
